
`timescale 1ns/10ps

module tb_uart;


//Globle Signals
parameter CLOCK_PERIOD = 10;
reg clk_sys,rst_n;
initial
begin
clk_sys = 1'b0;
rst_n = 1'b1;
#(CLOCK_PERIOD*10) rst_n = 1'b0;
#(CLOCK_PERIOD*10) rst_n = 1'b1;
end
always #(CLOCK_PERIOD/2) clk_sys <= ~clk_sys;


//DUT
wire        uart_channel;

reg         uart_tx_wr;
reg   [7:0] uart_tx_data;
wire        uart_tx_busy;

wire  [7:0] uart_rx_data;
wire        uart_rx_vld;
wire  [1:0] uart_rx_err;

wire [31:0] uart_conf = {20'h0,4'h1,4'h1,4'hC};

uart_tx t_uart(

    //Transmit Data
    .txd(uart_channel),

    //Uart Transmit Access Interface
    .uart_tx_wr(uart_tx_wr),
    .uart_tx_data(uart_tx_data),
    .uart_tx_busy(uart_tx_busy),

    //Configuration
    .uart_conf(uart_conf),

    .clk_sys(clk_sys),
    .rst_n(rst_n)
    
    );
    
uart_rx r_uart(

    //Receive Data
    .rxd(uart_channel),

    //Uart Receive Access Interface
    .uart_rx_data(uart_rx_data),
    .uart_rx_vld(uart_rx_vld),
    .uart_rx_err(uart_rx_err),

    //Configuration
    .uart_conf(uart_conf),

    .clk_sys(clk_sys),
    .rst_n(rst_n)
    
    );


//Test State Machine
reg [1:0] sta_test;
localparam IDLE = 2'h0,
           WAIT = 2'h1,
           TRAN = 2'h2,
           DONE = 2'h3;
           
reg [15:0] cnt_wait;
always @ (posedge clk_sys or negedge rst_n) 
begin
if (rst_n == 1'b0)
    sta_test <= IDLE;
else
    begin
    case (sta_test)
        IDLE:
            sta_test <= WAIT;
        WAIT:
            if (cnt_wait == 16'hF)
                sta_test <= TRAN; 
        TRAN:
            sta_test <= DONE;
        DONE:
            if (cnt_wait == 16'h3FF)
                sta_test <= WAIT;            
    endcase
    end
end


//Test Counter 
always @ (posedge clk_sys or negedge rst_n) 
begin
if (rst_n == 1'b0)
    cnt_wait <= 16'h0;
else
    begin
    case (sta_test)
        WAIT:
            if (uart_tx_busy == 1'b0)
                cnt_wait <= cnt_wait + 16'h1;
        DONE:
            cnt_wait <= cnt_wait + 16'h1;
        default:
            cnt_wait <= 16'h0;
    endcase
    end
end


//Test Data
reg [7:0] data_seed;
always @ (posedge clk_sys)
    if (sta_test == IDLE) data_seed <= 8'h75;

always @ (posedge clk_sys or negedge rst_n) 
begin
if (rst_n == 1'b0)
    uart_tx_data <= 8'h0;
else
    begin
    case (sta_test)
        IDLE:
            uart_tx_data <= data_seed; 
        TRAN:
            uart_tx_data <= {uart_tx_data[6:0],uart_tx_data[7] ^ uart_tx_data[6]};
    endcase
    end
end
always @ (posedge clk_sys or negedge rst_n) 
begin
if (rst_n == 1'b0)
    uart_tx_wr <= 1'b0;
else
    uart_tx_wr <= (sta_test == TRAN) ? 1'b1 : 1'b0;
end


//Test Result
reg [7:0] data_tested;
always @ (posedge clk_sys)
    if (uart_tx_wr) data_tested <= uart_tx_data;

always @ (posedge clk_sys) 
begin
if (uart_rx_vld)
    begin
    if (uart_rx_data == data_tested)
        $display("Uart Data Right!\n");   
    else
        $display("Uart Data Wrong!\n");
    end
end
always @ (posedge clk_sys) 
begin
case (uart_rx_err)
    2'h0: if (uart_rx_vld) $display("Parity Check Pass!\n");
    2'h1: if (uart_rx_vld) $display("Parity Check Fail!\n");
    2'h2: $display("Start Bit Error!\n");
    2'h3: $display("Stop Bit Error!\n");
endcase
end


//Debussy Simulation Wave File
initial
begin
$fsdbDumpfile("wave.fsdb");
$fsdbDumpvars;
end


endmodule
